﻿using System;
using System.Text;

namespace FATLib
{
    public struct BootSector
    {
        string oem_name;
        public short bytes_per_sector;
        public byte sectors_per_cluster;
        short reserved_sector_count;
        byte fat_count;
        short max_root_directory_entries;
        int total_sectors;
        byte media_descriptor;
        int sectors_per_fat;

        string volume_label;
        string file_system_type;

        public byte fat;

        public BootSector( byte[] buff )
        {
            oem_name = Encoding.ASCII.GetString( buff, 0x03, 8 );
            bytes_per_sector = BitConverter.ToInt16( buff, 0x0B );
            sectors_per_cluster = buff[0x0D];
            reserved_sector_count = BitConverter.ToInt16( buff, 0x0E );
            fat_count = buff[0x10];
            max_root_directory_entries = BitConverter.ToInt16( buff, 0x11 );
            total_sectors = BitConverter.ToInt16( buff, 0x13 );
            media_descriptor = buff[0x15];
            sectors_per_fat = BitConverter.ToInt16( buff, 0x16 );

            // we're dealing with a real badass here (FAT32)
            if( max_root_directory_entries == 0 )
            {
                total_sectors = BitConverter.ToInt32( buff, 0x20 );
                sectors_per_fat = BitConverter.ToInt32( buff, 0x24 );
                volume_label = Encoding.ASCII.GetString( buff, 0x47, 11 );
                file_system_type = Encoding.ASCII.GetString( buff, 0x52, 8 );
                fat = 32;
            }
            else
            {
                volume_label = Encoding.ASCII.GetString( buff, 0x2B, 11 );
                file_system_type = Encoding.ASCII.GetString( buff, 0x36, 8 );
                fat = 16; // i don't care about fat12
            }
        }

        public long GetFatStart()
        {
            return reserved_sector_count * bytes_per_sector;
        }
        public long GetFatSize()
        {
            return sectors_per_fat * bytes_per_sector;
        }

        public long GetSizeOfSystemAreaInClusters()
        {
            return GetSizeOfSystemAreaInSectors() / sectors_per_cluster;
        }

        public long GetSizeOfSystemAreaInSectors()
        {
            return reserved_sector_count + fat_count * sectors_per_fat;
        }

        public long GetSizeOfSystemAreaInBytes()
        {
            return GetSizeOfSystemAreaInSectors() * bytes_per_sector;
        }

        public long GetClusterSize()
        {
            return this.bytes_per_sector * this.sectors_per_cluster;
        }

        public override string ToString()
        {
            return String.Format( "OEM name: {0}\r\nBytes per sector: {1}\r\nSectors per cluster: {2}", this.oem_name, this.bytes_per_sector, this.sectors_per_cluster );
        }
    }
}